package com.gitee.wsl.security.hash.bcrypt

import com.gitee.wsl.lang.bytearray.Bytes
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith


class BCryptParserTest {
    private lateinit var parser: BCryptParser

    @BeforeTest
    fun setUp() {
        parser = BCryptParser.Default(Radix64Encoder.Default())
    }

    @Test
    @Throws(Exception::class)
    fun parseDifferentCostFactors() {
        for (cost in 4..9) {
            val salt: ByteArray = Bytes.random(16).array()
            val hash: ByteArray = BCrypt.withDefaults().hash(cost, salt, "12345".encodeToByteArray())

            val parts: BCrypt.HashData = parser.parse(hash)
            assertEquals(cost, parts.cost)
            assertEquals(BCrypt.Version.VERSION_2A, parts.version)
            assertContentEquals(salt, parts.rawSalt)
            assertEquals(23, parts.rawHash.size)

            println(parts)
        }
    }

    @Test
    @Throws(Exception::class)
    fun parseDifferentVersions() {
        for (version in BCrypt.Version.SUPPORTED_VERSIONS) {
            val salt = Bytes.random(16).array()
            val hash = BCrypt.with(version).hash(6, salt, "hs61i1oAJhdasdÄÄ".encodeToByteArray())
            val parts: BCrypt.HashData = parser.parse(hash)
            assertEquals(version, parts.version)
            assertEquals(6, parts.cost)
            assertContentEquals(salt, parts.rawSalt)
            assertEquals(23, parts.rawHash.size)

            println(parts)
        }
    }

    @Test
    @Throws(Exception::class)
    fun parseDoubleDigitCost() {
        val salt= Bytes.random(16).array()
        val hash= BCrypt.with(BCrypt.Version.VERSION_2A)
            .hash(11, salt, "i27ze8172eaidh asdhsd".encodeToByteArray())
        val parts= parser.parse(hash)
        assertEquals(BCrypt.Version.VERSION_2A, parts.version)
        assertEquals(11, parts.cost)
        assertContentEquals(salt, parts.rawSalt)
        assertEquals(23, parts.rawHash.size)

        println(parts)
    }

    @Test
    @Throws(Exception::class)
    fun parseErrorMissingVersion() {
        parser.parse("$06\$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i".encodeToByteArray())
    }

    @Test
    @Throws(Exception::class)
    fun parseErrorMissingLeadingZero() {
        parser.parse("$2a$6\$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i".encodeToByteArray())
    }

    @Test
    @Throws(Exception::class)
    fun parseErrorMissingSeparator() {
        parser.parse("$2a$06If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i".encodeToByteArray())
    }

    @Test
    @Throws(Exception::class)
    fun parseErrorMissingSeparator2() {
        parser.parse("$2a06\$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i".encodeToByteArray())
    }

    @Test
    @Throws(Exception::class)
    fun parseErrorInvalidVersion() {
        parser.parse("$2$06\$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i".encodeToByteArray())
    }

    @Test//(expected = IllegalBCryptFormatException::class)
    @Throws(Exception::class)
    fun parseErrorInvalidVersion2() {
        parser.parse("$3a$06\$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i".encodeToByteArray())
    }

    @Test//(expected = IllegalBCryptFormatException::class)
    @Throws(Exception::class)
    fun parseErrorInvalidVersion3() {
        parser.parse("$2l$06\$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i".encodeToByteArray())
    }

    @Test//(expected = IllegalBCryptFormatException::class)
    @Throws(Exception::class)
    fun parseErrorMissingSaltAndHas() {
        parser.parse("$2a$06$".encodeToByteArray())
    }

    @Test//(expected = IllegalBCryptFormatException::class)
    @Throws(Exception::class)
    fun parseErrorMissingHash() {
        parser.parse("$2a$06\$If6bvum7DFjUnE9p2uDeDu".encodeToByteArray())
    }

    @Test//(expected = IllegalBCryptFormatException::class)
    @Throws(Exception::class)
    fun parseErrorMissingChar() {
        parser.parse("$2a$06\$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0".encodeToByteArray())
    }

    @Test//(expected = IllegalBCryptFormatException::class)
    @Throws(Exception::class)
    fun parseErrorTooLong() {
        parser.parse("$2a$06\$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i9".encodeToByteArray())
    }



    @Test
    @Throws(Exception::class)
    fun parseErrorZeroLengthHash() {
        assertFailsWith(IllegalArgumentException::class){
            parser.parse(ByteArray(0))
        }
    }

    @Test
    @Throws(Exception::class)
    fun parseErrorWayTooShort() {
        assertFailsWith(IllegalBCryptFormatException::class) {
            parser.parse("$2a".encodeToByteArray())
        }
    }

    @Test
    fun parseErrorTooLongGetExceptionMessage() {
        try {
            parser.parse("$2a$06\$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i9".encodeToByteArray())
            //fail()
        } catch (e: IllegalBCryptFormatException) {
//            assertNotNull(e.getMessage())
//            assertTrue(e.getMessage().length() > 20)
            println(e.message)
        }
    }
}
